library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity IF_UNIT is
	Port (
        CLK : in STD_LOGIC;

        PC : in STD_LOGIC_VECTOR(31 downto 0);
		  STALL_FROM_DECODE : in STD_LOGIC; -- stall signal originating from decode.
		  FLUSH_FROM_DECODE : in STD_LOGIC; -- Flush from decode (for branch/jump etc)

        PC_OUT : out STD_LOGIC_VECTOR(31 downto 0); --- REGSISTERED output
		  PC_COMBI_OUT : out STD_LOGIC_VECTOR(31 downto 0); --- COMBINATORIAL output
        INS : out STD_LOGIC_VECTOR(31 downto 0)
        );
end IF_UNIT;

architecture Behavioral of IF_UNIT is

	 -- 4k bytes, 1024 instructions.
	 -- address starts from 0x00400000
	 -- = 0b (0000 0000 0100 0000 0000 0000 0000 0000), ends at 0x00040000 + 0x0001000-1 = 0x0041000 -1 = 0x00400999
	 
	 -- CS = 0x00400xxx
	 
    component ISMEM is
    Port (
        addr : in STD_LOGIC_VECTOR (9 downto 0);
        rdata : out STD_LOGIC_VECTOR (31 downto 0)
        );
    end component;
	
	 signal ROM_CHIP_SELECT : STD_LOGIC;

	 signal incremented_pc : STD_LOGIC_VECTOR(31 downto 0);
	 
    signal ins_data : STD_LOGIC_VECTOR(31 downto 0);
begin
    rom_guy : ISMEM
    PORT MAP(
        addr => pc(11 downto 2),
        rdata => ins_data
    );

	 ROM_CHIP_SELECT <= '1' when pc(31 downto 12) = x"00400" else '0';
	 incremented_pc <= STD_LOGIC_VECTOR(unsigned(PC) + 4);
	 PC_COMBI_OUT <= incremented_pc;
	
    process (CLK)
    begin
        if clk'event and clk = '1' then
				if (FLUSH_FROM_DECODE = '1') then
						PC_OUT <= incremented_pc; -- (not very important, since we would be changing this anw)
						INS <= x"00000000";
				-- Address decoding for ROM
				elsif (ROM_CHIP_SELECT <= '1') then
					if(STALL_FROM_DECODE = '0') then -- Only update the buffer when there is no stall (assuming there is no branch/jmp)
						PC_OUT <= incremented_pc;
						INS <= ins_data;
					end if;
				end if;
        end if;
    end process;
end Behavioral;